package body Legend.Grps is

   procedure Open (
      this       : in out Group_File_Type;
      Index_File : String;
      Data_File  : String;
      Readonly   : Boolean := True
      )
   is
      use type Stream_IO.Count;
   begin
      Stream_IO.Open (
         File => this.Index_File, 
         Name => Index_File, 
         Mode => Stream_IO.In_File);
      this.Index_Size := Stream_IO.Size(this.Index_File);
      this.Index_Stream := Stream_IO.Stream(this.Index_File);
      this.Index_Count := Uint16_t(this.Index_Size / 4);
      Stream_IO.Open (
         File => this.Data_File,
         Name => Data_File,
         Mode => (if Readonly then Stream_IO.In_File else Stream_IO.Out_File));
      this.Data_Size := Stream_IO.Size(this.Data_File);
      this.Data_Stream := Stream_IO.Stream(this.Data_File);
      this.Current_Data_Offset := 1;
      this.Next_Data_Offset := 1;
      this.Block_Size := 0;
      if not Readonly then
         this.Set_Writable;
      end if;
   end Open;

   procedure Set_Block_Index (
      this  : in out Group_File_Type; 
      index : Uint16_t
      )
   is
      use type Stream_IO.Count;
   begin
      if index >= this.Index_Count then
         raise Constraint_Error with "block index out of range";
      end if;
      if index = 0 then
         this.Next_Data_Offset := 1;
         Stream_IO.Set_Index(this.Index_File, 1);
      else
         Stream_IO.Set_Index(this.Index_File, Stream_IO.Count(index * 4 - 3));
         this.Next_Data_Offset := Stream_IO.Count(int32_t'Input(this.Index_Stream)) + 1;
      end if;
      this.Next_Block;
   end Set_Block_Index;

   procedure Next_Block (this : in out Group_File_Type)
   is
      use type Stream_IO.Count;
   begin
      this.Current_Data_Offset := this.Next_Data_Offset;
      this.Next_Data_Offset := Stream_IO.Count(int32_t'Input(this.Index_Stream)) + 1;
      if this.Next_Data_Offset > this.Current_Data_Offset then
         this.Block_Size := this.Next_Data_Offset - this.Current_Data_Offset;
      else
         this.Block_Size := 0;
      end if;
      if not this.End_Of_Data then
         Stream_IO.Set_Index (this.Data_File, this.Current_Data_Offset);
      end if;
   end Next_Block;

   function End_Of_Data (this : Group_File_Type) return Boolean
   is
      pragma Inline (End_Of_Data);
      use type Stream_IO.Count;
   begin
      return this.Current_Data_Offset > this.Data_Size;
   end End_Of_Data;

   procedure Close (this : in out Group_File_Type)
   is
   begin
      Stream_IO.Close (this.Data_File);
      Stream_IO.Close (this.Index_File);
   end Close;

   procedure Set_Writable (this : in out Group_File_Type)
   is
   begin
      Stream_IO.Set_Mode(this.Data_File, Stream_IO.Out_File);
   end Set_Writable;

end Legend.Grps;
